<!DOCTYPE html>
<!-- saved from url=(0095)https://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics?display=Print -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Custom Controls in Win32 API: The Basics - CodeProject</title> 
	<link type="text/css" rel="stylesheet" href="./Custom Controls in Win32 API_ The Basics - CodeProject_files/Main.min.css">

	
<meta http-equiv="content-language" content="en-US">

<meta name="Description" content="A quick introduction into the development of custom controls in plain Win32 API.; Author: Martin Mitáš; Updated: 12 Dec 2014; Section: Windows API; Chapter: Platforms, Frameworks &amp; Libraries; Updated: 12 Dec 2014">
<meta name="Keywords" content="C, Windows, Win32, Win64, Visual-Studio, Dev, VS2010, custom-controls,Windows API,Platforms, Frameworks &amp; Libraries,Free source code, tutorials">
<meta name="Author" content="Martin Mitáš">
<meta name="Rating" content="General">
<meta name="Revisit-After" content="1 days">
<meta name="application-name" content="CodeProject">
<meta name="google-translate-customization" content="d908bb7ce7aff658-4c2f3a504525c916-g629383f736781a8a-13">

<link rel="dns-prefetch" href="https://ajax.googleapis.com/"> 
<link rel="canonical" href="https://www.codeproject.com/Articles/559385/%2fArticles%2f559385%2fCustom-Controls-in-Win-API-The-Basics">
<link rel="alternate" type="application/rss+xml" title="CodeProject Latest articles - All Topics" href="https://www.codeproject.com/WebServices/ArticleRSS.aspx?cat=1">
<link rel="alternate" type="application/rss+xml" title="CodeProject Latest articles - Artificial Intelligence" href="https://www.codeproject.com/WebServices/ArticleRSS.aspx?cat=31">
<link rel="alternate" type="application/rss+xml" title="CodeProject Lounge Postings" href="https://www.codeproject.com/webservices/LoungeRSS.aspx">
<meta name="robots" content="index, follow">
<link rel="search" type="application/opensearchdescription+xml" title="CodeProject" href="https://www.codeproject.com/info/OpenSearch.xml">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link rel="apple-touch-icon" sizes="144x144" href="https://www.codeproject.com/favicon/apple-touch-icon.png"> 
<link rel="icon" type="image/png" sizes="32x32" href="https://www.codeproject.com/favicon/favicon-32x32.png"> 
<link rel="icon" type="image/png" sizes="16x16" href="https://www.codeproject.com/favicon/favicon-16x16.png"> 
<link rel="manifest" href="https://www.codeproject.com/favicon/manifest.json"> 
<link rel="mask-icon" href="https://www.codeproject.com/favicon/safari-pinned-tab.svg" color="#ff9900">
	
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "TechArticle",
  "headline": "Custom Controls in Win32 API: The Basics",
  "url": "https://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics",
  "discussionUrl": "https://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics",
  "isFamilyFriendly": "true",
  "image": "https://codeproject.global.ssl.fastly.net/App_Themes/CodeProject/Img/Article100.png",
  "keywords": "C, Windows, Win32, Win64, Visual-Studio (VS2010), custom-controls",
  "commentCount": "26",
  "editor" : {
    "@type" : "Person",
    "name" : "Martin Mitáš",
    "url" : "https://www.codeproject.com/script/Membership/View.aspx?mid=5807385"
  },
  "license": "http://www.codeproject.com/info/cpol10.aspx",
  "publisher" : {
    "@type" : "Organization",
    "name" : "CodeProject"
  }
  "description": "A quick introduction into the development of custom controls in plain Win32 API.",
  "upvoteCount": "60",
  "articleSection": "Windows API",
  "author" : [{
      "@type" : "Person",
      "name" : "Martin Mitáš",
      "url" : "https://www.codeproject.com/script/Membership/View.aspx?mid=5807385"
    }],
  "datePublished": "2013-07-07",
  "dateCreated": "2013-07-07",
  "dateModified": "2014-12-12",
  "aggregateRating" : {
    "@type" : "aggregateRating",
    "ratingValue" : 4.95,
    "ratingCount" : 61,
    "bestRating" : 5,
    "worstRating" : 1
  },
}
</script>
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "item" : {
      "@id" : "/Chapters/8/Platforms-Frameworks-Libraries.aspx",
      "name" : "Platforms, Frameworks & Libraries"
    }
  },{
    "@type": "ListItem",
    "position": 2,
    "item" : {
      "@id" : "/KB/vista/",
      "name" : "Windows API"
    }
  }]
}
</script>
	<!--<base target="_top">--><base href="." target="_top">
	<script type="text/javascript" src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/jquery.2.2.4.min.js.下载"></script><script type="text/javascript">//<![CDATA[
if (typeof jQuery == 'undefined') {
    document.write(unescape("%3Cscript src='%2fscript%2fJS%2fjquery-2.2.4.min.js' type='text/javascript' %3E%3C/script%3E"));
}//]]></script><script src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/jquery-2.2.4.min.js.下载" type="text/javascript"></script>
<script type="text/javascript">//<![CDATA[
function defrm () { /* thanks twitter */ document.write = ''; window.top.location = window.self.location;  setTimeout(function() { document.body.innerHTML = ''; }, 0);  window.self.onload = function(evt) { document.body.innerHTML = ''; }; }if (window.top !== window.self) {  try {  if (window.top.location.host) { /* will throw */ } else { defrm(); /* chrome */ }  } catch (ex) { defrm(); /* everyone else */ } }if (typeof(DemoUrl)!='undefined')   document.write(unescape('%3Cme')+'ta http'+'-equiv="re'+'fresh"                  con'+'tent="1;url='+DemoUrl+unescape('"%3CE'));

//]]>
</script>

	




<script type="text/javascript">
	var _gaq = _gaq || [];
	_gaq.push(['_setAccount', 'UA-1735123-1']);
	_gaq.push(['_trackPageview']);
	_gaq.push(['_setDomainName', 'www.codeproject.com']);
	_gaq.push(['_setSessionTimeout', '1200']); 

	(function () {
		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
		(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
	})(); 
</script><script type="text/javascript" async="" src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/ga.js.下载"></script>


</head>	

<body class="chrome chrome67 touch">

<a class="access-link" href="https://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics?display=Print#Main"><img alt="Click here to Skip to main content" src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/t.gif"></a>





<div class="page-background">

	
	

	

	
    <div id="ctl00_STM" class="site-top-menu fluid">
        <div class="main-content">
            
        </div>
    </div>

	
    <div id="ctl00_SH" class="site-header fluid">
        <div class="main-content">
            <div class="logo"><a href="https://www.codeproject.com/"><img id="ctl00_Logo" tabindex="1" title="CodeProject" src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/logo250x135.gif" alt="Home" style="height:135px;width:250px;border-width:0px;"></a></div>
            <div class="promo"></div>
        </div>
    </div>

	<a href="https://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics?display=Print#Main"><img alt="Click here to Skip to main content" class="access-link" src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/t.gif"></a>

	
			
	

	<div id="A" class="container-content-wrap fluid print"> 
	<div class="container-content">


		<div class="clearfix">
			<div class="container-breadcrumb float-left ">
				<div><a href="https://www.codeproject.com/script/Content/SiteMap.aspx">Articles</a> » <a href="https://www.codeproject.com/Chapters/8/Platforms-Frameworks-Libraries.aspx">Platforms, Frameworks &amp; Libraries</a> » <a href="https://www.codeproject.com/KB/vista/">Windows API</a> » <a href="https://www.codeproject.com/KB/vista/#General">General</a></div>
			</div>

            <div class="float-left">
				
			</div>

			<div class="edit-links float-right">
				
			</div>

			<div class="article-nav float-right">
                
				
			</div>
		</div>

		<table class="extended container-article-parts" cellpadding="0" cellspacing="0">
        <tbody><tr valign="top">
		<td width="117px" class="article-wing-left">

			

		</td>
		<td>
			
			<div id="AT" class="container-article  fluid tight"> 

				<div class="article">

					<form name="aspnetForm" method="post" action="https://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics?display=Print" id="aspnetForm" style="margin:0;padding:0">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="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">
</div>

<div>

	<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="10C1FD69">
</div>

					
					 
					<div class="header">
					    <a name="Main"></a>

					    
					    <a name="_articleTop" id="_articleTop"></a>
					    <div class="title">
					        <h1 id="ctl00_ArticleTitle">Custom Controls in Win32 API: The Basics</h1>
					    </div>

                        <div style="height:34px">
					        
					        <div class="entry float-left">

                                <img src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/58de2d085c17e28b8951315245dd408c.jpeg" id="ctl00_avatar" class="float-left avatar">

                                <div class="float-left">
                                    <div>
						                <span class="author"><a href="https://www.codeproject.com/script/Membership/View.aspx?mid=5807385" rel="author">Martin Mitáš</a></span>, 
						                <span class="date" title="Date last updated">
							            12 Dec 2014</span>
			                        </div>

                                    
						            
    						        	

                                </div>

    	                        	
                                <div class="float-left" style="margin: 25px 0 0 10px;">
	                                
	                            </div>
                         	    	
    
					        </div>

                            

						    <div id="ctl00_AdManagerWrap" class="float-right align-center">
                                
						    </div>

                        </div>

                        <div id="ctl00_description" class="summary">A quick introduction into the development of custom controls in plain Win32 API.</div><span id="ctl00_thumbnailUrl" class="date" content="https://codeproject.global.ssl.fastly.net/script/Articles/Images/article100x80.png"></span>			

                    </div>
                    
					
					

					

					
					
					

						
					

					

						
						<div id="contentdiv" class="text">
						



<ul class="download">
	<li><a href="https://www.codeproject.com/KB/vista/559385/trivial.zip">Download Trivial Control Example - 16.3 KB</a></li></ul>

<h2>Articles in this series</h2>

<ul>
	<li>Custom Controls in Win32 API: The Basics</li>	<li><a href="http://www.codeproject.com/Articles/617212/Custom-Controls-in-Win32-API-The-Painting">Custom Controls in Win32 API: The Painting</a></li>	<li><a href="http://www.codeproject.com/Articles/620045/Custom-Controls-in-Win32-API-Visual-Styles">Custom Controls in Win32 API: Visual Styles</a></li>	<li><a href="http://www.codeproject.com/Articles/624495/Custom-Controls-in-Win32-API-Standard-Messages">Custom Controls in Win32 API: Standard Messages</a></li>	<li><a href="http://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization">Custom Controls in Win32 API: Control Customization</a></li>	<li><a href="http://www.codeproject.com/Articles/744603/Custom-Controls-in-Win-API-Encapsulation-of-Cust">Custom Controls in Win32 API: Encapsulation of Customized Controls</a></li>	<li><a href="http://www.codeproject.com/Articles/1042516/Custom-Controls-in-Win-API-Scrolling">Custom Controls in Win32 API: Scrolling</a></li></ul>

<h2>Introduction</h2>

<p>A large portion (if not all) of textbooks and tutorials about Win32 API programming touch also the topic of implementing a custom control. However AFAIK, there is no really comprehensive source (or at least none known to me) covering more than just the very basics of this topic.</p>

<p>Most of such sources just provide some information on how to register a new window class, a trivial information about a few messages, most notably <code>WM_PAINT</code>, and then they switch to another topic. If you have ever tried to implement your own non-trivial control, I'm pretty sure you can agree with me that the implementor of the control must know much more, and that many traps are awaiting on the way.</p>

<p>This article is intended as a first part of a series which will eventually try to cover the topic more thoroughly, including best practices, which you will hopefully find useful in order to implement good custom controls, which are easy to use by application developers, which fit into the Windows look and feel and which contribute to good applications.</p>

<p>As this is the first part of the series, it will summarize the basics, and hence it will eventually be just a variant of the other sources I criticized in the previous sentences. I can only hope that the dear readers will forgive me for the slow start.</p>

<h2>Few Notes</h2>

<p>This article (and the whole series) is intended for Windows developers who know the C language and who are familiar at least with the basics of the Windows API. You should know terms like "message loop", "window procedure", or "window class" and be familiar with these concepts.</p>

<p>Note that the articles will be accompanied by some C code samples. The code is created more for better illustration rather than for completeness of implementation. Especially note that to improve readability, error handling is mostly omitted. Real applications should of course handle errors more seriously.</p>

<p>Throughout the series, the code samples will follow a few code conventions about identifiers related to the control being implemented:</p>

<ul>
	<li><code>XXS_STYLE</code>: We will use the prefix <code>XXS_</code> for custom control specific style bits.</li>	<li><code>XXM_MESSAGE</code>: We will use the prefix <code>XXM_</code> for custom control specific messages.</li>	<li><code>XXN_NOTIFICATION</code>: We will use the prefix <code>XXN_</code> for custom control specific notification codes.</li></ul>

<h2>Trivial Control</h2>

<p>We will start with a code implementing a very trivial custom control. It can also serve as a skeleton for your experiments. It consists of three source files. The first file is a header describing the control interface. So far it is very simple as it actually does not provide any interesting functionality.</p>

<p>The code below roughly corresponds to the state of things where the other sources I criticized in the first few lines, so I believe no detailed comments are needed.</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> File custom.h
 * (custom control interface)
 */</span>

<span class="code-preprocessor">#ifndef CUSTOM_H
</span><span class="code-preprocessor">#define CUSTOM_H
</span>
<span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">tchar.h</span><span class="code-keyword">&gt;</span>
</span><span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">windows.h</span><span class="code-keyword">&gt;</span>
</span>

<span class="code-comment">/*</span><span class="code-comment"> Window class */</span>
<span class="code-preprocessor">#define CUSTOM_WC   _T("CustomControl")
</span>
<span class="code-comment">/*</span><span class="code-comment"> Register/unregister the window class */</span>
<span class="code-keyword">void</span> CustomRegister(<span class="code-keyword">void</span>);
<span class="code-keyword">void</span> CustomUnregister(<span class="code-keyword">void</span>);


<span class="code-preprocessor">#endif  /* CUSTOM_H */</span></pre>

<p>Here is the custom control implementation:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> File custom.c
 * (custom control implementation)
 */</span>

<span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-string">"</span><span class="code-string">custom.h"</span>
</span>

<span class="code-keyword">static</span> <span class="code-keyword">void</span>
CustomPaint(HWND hwnd)
{
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    GetClientRect(hwnd, &amp;rect);

    hdc = BeginPaint(hwnd, &amp;ps);
    SetTextColor(hdc, RGB(<span class="code-digit">0</span>,<span class="code-digit">0</span>,<span class="code-digit">0</span>));
    SetBkMode(hdc, TRANSPARENT);
    DrawText(hdc, _T(<span class="code-string">"</span><span class="code-string">Hello World!"</span>), -<span class="code-digit">1</span>, &amp;rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
    EndPaint(hwnd, &amp;ps);
}


<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-keyword">case</span> WM_PAINT:
            CustomPaint(hwnd);
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;
    }
    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}

<span class="code-keyword">void</span>
CustomRegister(<span class="code-keyword">void</span>)
{
    WNDCLASS wc = { <span class="code-digit">0</span> };

    wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = CustomProc;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszClassName = CUSTOM_WC;
    RegisterClass(&amp;wc);
}

<span class="code-keyword">void</span>
CustomUnregister(<span class="code-keyword">void</span>)
{
    UnregisterClass(CUSTOM_WC, NULL);
}</pre>

<p>And finally a simple application using the control:</p>

<pre lang="C"><span class="code-comment">/*</span><span class="code-comment"> File main.c
 * (application doing actually nothing but creating a main window and
 *  the custom control as its only child)
 */</span>

<span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">tchar.h</span><span class="code-keyword">&gt;</span>
</span><span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-keyword">&lt;</span><span class="code-leadattribute">windows.h</span><span class="code-keyword">&gt;</span>
</span>
<span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-string">"</span><span class="code-string">custom.h"</span>
</span>

<span class="code-keyword">static</span> HINSTANCE hInstance;
<span class="code-keyword">static</span> HWND hwndCustom;

<span class="code-preprocessor">#define CUSTOM_ID     100
</span><span class="code-preprocessor">#define MARGIN          7
</span>
<span class="code-keyword">static</span> LRESULT CALLBACK
MainProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-keyword">case</span> WM_SIZE:
            <span class="code-keyword">if</span>(wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED) {
                WORD cx = LOWORD(lParam);
                WORD cy = HIWORD(lParam);
                SetWindowPos(hwndCustom, NULL, MARGIN, MARGIN,
                             cx-<span class="code-digit">2</span>*MARGIN, cy-<span class="code-digit">2</span>*MARGIN, SWP_NOZORDER);
            }
            <span class="code-keyword">break</span>;

        <span class="code-keyword">case</span> WM_CREATE:
            hwndCustom = CreateWindow(CUSTOM_WC, NULL, WS_CHILD | WS_VISIBLE,
                                  <span class="code-digit">0</span>, <span class="code-digit">0</span>, <span class="code-digit">0</span>, <span class="code-digit">0</span>, hwnd, (HMENU) CUSTOM_ID, hInstance, NULL);
            <span class="code-keyword">break</span>;

        <span class="code-keyword">case</span> WM_CLOSE:
            PostQuitMessage(<span class="code-digit">0</span>);
            <span class="code-keyword">break</span>;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}

<span class="code-keyword">int</span> APIENTRY
_tWinMain(HINSTANCE hInst, HINSTANCE hInstPrev, TCHAR* lpszCmdLine, <span class="code-keyword">int</span> iCmdShow)
{
    WNDCLASS wc = { <span class="code-digit">0</span> };
    HWND hwnd;
    MSG msg;

    hInstance = hInst;

    CustomRegister();

    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = MainProc;
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + <span class="code-digit">1</span>);
    wc.lpszClassName = _T(<span class="code-string">"</span><span class="code-string">MainWindow"</span>);
    RegisterClass(&amp;wc);

    hwnd = CreateWindow(_T(<span class="code-string">"</span><span class="code-string">MainWindow"</span>), _T(<span class="code-string">"</span><span class="code-string">App Name"</span>), WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT, <span class="code-digit">350</span>, <span class="code-digit">250</span>, NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd, iCmdShow);

    <span class="code-keyword">while</span>(GetMessage(&amp;msg, NULL, <span class="code-digit">0</span>, <span class="code-digit">0</span>)) {
        <span class="code-keyword">if</span>(IsDialogMessage(hwnd, &amp;msg))
            <span class="code-keyword">continue</span>;

        TranslateMessage(&amp;msg);
        DispatchMessage(&amp;msg);
    }

    CustomUnregister();

    <span class="code-keyword">return</span> (<span class="code-keyword">int</span>)msg.wParam;
}</pre>

<p>(There is MS Visual Studio 2010 project with these sources attached at the top of this article.)</p>

<h2>Window Class and CS_GLOBALCLASS</h2>

<p>Assuming you are able to implement simple Windows applications, there is not much what should surprise you in the preceding code: The custom control is implemented in a very similar way as a typical application window of your first Win32 Hello World program. Its window class must be registered before creation and usage of the window belonging to that class and there is the well known window procedure.</p>

<p>Probably the only difference is the class style <code>CS_GLOBALCLASS</code>, which makes the window class <em>global</em>. Actually if the implemented control is registered and used in a single module (e.g., it is both registered and used in the EXE, or a single DLL) you do not need to use it (and actually you should not), and instead you should set <code>WNDCLASS::hInstance</code> to the handle of the module. It is the <code>HINSTANCE</code> handle passed into <code>WinMain()</code>, or <code>DllMain()</code> in case of a DLL. Then, when you create the control, you then have to specify the same instance handle.</p>

<p>However nowadays many applications consist of more then one program, and even more they often use many DLLs, perhaps even supporting some plug-ins (DLLs loaded ad-hoc) which may need to reuse the control, and in such cases the <code>CS_GLOBALCLASS</code> is very handy: When you use it the system finds the class even if the instance handle passed to <code>CreateWindow()</code> does not match the one when the control window class has been registered.</p>

<p>When <code>CreateWindow()</code> (or <code>CreateWindowEx()</code>) is called, the system first looks for the specified local class (i.e., a window class which was registered without the flag <code>CS_GLOBALCLASS</code> and with the matching <code>HINSTANCE</code> handle). If it is not found, it searches the global classes (i.e., classes with the style <code>CS_GLOBALCLASS</code>).</p>

<p>This means that classes with the style <code>CS_GLOBALCLASS</code> in the whole process share one common namespace, and they even can be shadowed locally by a local window class registered with a particular <code>HINSTANCE</code> handle. Also note all the standard controls from <em>USER32.DLL</em> and <em>COMCTL32.DLL</em> use this class style too so it is really wise to avoid those names for your local classes (unless the shadowing is what you really want to achieve, of course.)</p>

<p>Hence, when registering a global class, you should be careful when choosing its name to minimize the accidental risk of shadowing it in some DLL. I recommend using the reversed domain name to produce unique class names (e.g., <code>"com.company.control"</code>) to minimize the risk of such name clash.</p>

<h2>Control Data</h2>

<p>A non-trivial custom control typically needs some memory where it can store its data and internal state. This is typically achieved by defining a structure which exists during the life time of the control. The pointer to a structure is usually stored within the extra bytes of the control window. The following code shows how to do that:</p>

<pre lang="C"><span class="code-keyword">typedef</span> <span class="code-keyword">struct</span> CustomData_tag CustomData;
<span class="code-keyword">struct</span> CustomData_tag {
    <span class="code-comment">//</span><span class="code-comment"> ... the control data</span>
};

<span class="code-keyword">void</span>
CustomRegister(<span class="code-keyword">void</span>)
{
    WNDCLASS wc = { <span class="code-digit">0</span> };

    wc.style = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = CustomProc;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszClassName = CC_WINDOWCLASS;
    wc.cbWndExtra = <span class="code-keyword">sizeof</span>(CustomData*);  <span class="code-comment">//</span><span class="code-comment"> &lt;-- Here we are</span>
    RegisterClass(&amp;wc);
}</pre>

<p>The window procedure of the control then can use <code>SetWindowLongPtr()</code> and <code>GetWindowLongPtr()</code> to setup and access the structure. The code below shows creation and destruction of the structure in an extended version of the window procedure from the introduction code above:</p>

<pre lang="C"><span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    <span class="code-comment">//</span><span class="code-comment"> Retrieve the pointer to the control data so it may be used in all message handlers below:</span>
    CustomData* pData = (CustomData*) GetWindowLongPtr(hwnd, <span class="code-digit">0</span>);

    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_NCCREATE:
            <span class="code-comment">//</span><span class="code-comment"> Allocate, setupo and remember the control data:</span>
            pData = malloc(<span class="code-keyword">sizeof</span>(CustomData));
            <span class="code-keyword">if</span>(pData == NULL)
                <span class="code-keyword">return</span> FALSE;
            SetWindowLongPtr(hwnd, <span class="code-digit">0</span>, (LONG_PTR)pData);
            <span class="code-comment">//</span><span class="code-comment"> ... initialize CustomData members</span>
            <span class="code-keyword">return</span> TRUE;

        <span class="code-keyword">case</span> WM_NCDESTROY:
            <span class="code-keyword">if</span>(pData != NULL) { <span class="code-comment">//</span><span class="code-comment"> &lt;-- "If" required as we get here even when WM_NCCREATE fails.</span>
                <span class="code-comment">//</span><span class="code-comment"> ... free any resources stored in the data structure</span>
                free(pData);
            }
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;
    }
    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p>I would like to highlight few things about this:</p>

<ul>
	<li>Many tutorials allocate (and free) the data in <code>WM_CREATE</code> (and <code>WM_DESTROY</code>). I recommend to use their "NC" counterparts as the code above shows. This is safer because during window creation <code>WM_NCCREATE</code> is the very first message sent and then several other messages are sent before the <code>WM_CREATE</code> eventually comes. If you would ever add a handler for such a message into your code, you might easily introduce a dereference of the <code>NULL</code> pointer, leading to well-known consequences: The application crashes. Similarly it is the message <code>WM_NCDESTROY</code> which is guaranteed to be the last message received when the control is being destroyed, and not <code>WM_DESTROY</code>.</li>	<li>Note that Windows here does not follow the common error handling pattern that release/terminate code is called only when the corresponding initialization has previously succeeded. If <code>WM_NCCREATE</code> fails (i.e., when it returns <code>FALSE</code>), Windows sends <code>WM_NCDESTROY</code> anyway. Hence the app has to make sure the pointer is not <code>NULL</code> befire trying to dereference the pointer in the <code>WM_NCDESTROY</code> handler. The same would stand for <code>WM_CREATE</code> and <code>WM_DESTROY</code>: if the former returns <code>-1</code>, the latter is called anyway.</li>	<li>Also many tutorials avoid using the "extra bytes" and use <code>GWL_USERDATA</code> as a parameter for <code>SetWindowLongPtr()</code> and <code>GetWindowLongPtr()</code>. However for general-purpose control this is a wrong idea as the control should leave the <code>GWL_USERDATA</code> for the application as it also may need to associate some additional data with the control for its own purpose.</li></ul>

<h2>Defining a Control Interface</h2>

<p>Of course, all controls providing useful functionality have to provide it through some interface. The interface of standard controls mostly consists of definition of their styles, extended styles, controls-specific messages, and notifications. The interface may also use normal functions, but as a believer in principle of consistency, I will follow the way of standard controls and stick mainly to messages and notifications.</p>

<p>So acutally all that is needed is to specify the numerical codes for the control-specific constants in the header file exposing the control interface. Let's take a look at each category a bit closer.</p>

<h3>Messages</h3>

<p>The control may receive some standard (system) messages which allow smooth intergation of the control into an application. Control-specific messages are used to change its internal state, to trigger some of its functionality, or to ask it for some data it may hold.</p>

<p>Win32 API defines several ranges for message codes, and you really should respect them if you want to avoid troubles:</p>

<ul>
	<li><strong>Range 0 through 0x03ff (<code>WM_USER-1</code>):</strong> The messages reserved by system. The control should respond to them as appropriate. Unless the control needs to do something special, it can generally pass them into <code>DefWindowProc()</code> and the function will care the message in a default way. Many system messages and how to handle them in your code will be of interest of some of sequel article.</li>	<li><strong>Range 0x0400 (<code>WM_USER</code>) through 0x7fff (<code>WM_APP-1</code>):</strong> This range is intended for messages specific to the control. You, as a designer of the control, typically define these in a header describing the control interface. Additionally I recommend to avoid using message codes in the range 0x2000 (<code>OCM_BASE</code>) through 0x23ff (<code>OCM_BASE+WM_USER-1</code>) as those are often used for a technique known as message reflection. (Perhaps we will get a closer look at that in some following article.)</li>	<li><strong>Range 0x8000 (<code>WM_APP</code>) through 0xbfff:</strong> You can use these if the custom control is only used internally by your application. Reusable general-purpose controls should avoid using this range and leave this range for control sub-classing by the application.</li>	<li><strong>Range 0xc000 through 0xffff: </strong>These are only for use together with <code>RegisterWindowMessage()</code>, and they are irrelevant for our topic.</li>	<li><strong>Messages above 0xffff</strong> are reserved by Microsoft.</li></ul>

<p>I.e., in most cases the control specific messages should fall into the range based by <code>WM_USER</code>.</p>

<pre><span class="code-preprocessor">#define XXM_DOSOMETHING          (WM_USER + 100)
</span><span class="code-preprocessor">#define XXM_DOSOMETHINGELSE      (WM_USER + 101)</span></pre>

<p>(The value 100 in the example above is just an arbitrary value to illustrate placing the messages somewhere in the control-scpecific message code range.)</p>

<p>To implement the message, you just add another branch into the window procedure:</p>

<pre><span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> XXM_DOSOMETHING:
            <span class="code-comment">//</span><span class="code-comment"> do something</span>
            <span class="code-keyword">return</span> TRUE;

        <span class="code-keyword">case</span> XXM_DOSOMETHINGELSE:
            <span class="code-comment">//</span><span class="code-comment"> do something else</span>
            <span class="code-keyword">return</span> FALSE;
    }

    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p>Last but not least, you should also make some documentation and describe what the messages actually do, how they interpret <code>wParam</code> and <code>lParam</code> propagated from <code>SendMessage()</code> (or other similar function), and how the application should interpret its return value.</p>

<h3>Styles</h3>

<p>The look and behavior of standard controls can also be determined by setting its style and extended styles. Both the style and the extended style are <code>DWORD</code> bitmasks associated with each window (<code>HWND</code>). Both bitmasks are set when the window is created: <code>CreateWindow()</code> sets the style as specified by one of its parameters and the extended style to zero, while <code>CreateWindowEx()</code> allows to specify both.</p>

<p>The application can also change both later with <code>SetWindowLong()</code> with <code>GWL_STYLE</code> and <code>GWL_EXSTYLE</code>, respectively.</p>

<p>The meaning of high word of the style, and all bits of the extended style is defined by the system and it is really a bad idea trying to override it. The custom control should respect those bits (as far as it makes sense to do in the context of the particular control) and behave in accordance to their meaning.</p>

<p>The low 16 bits of the style are available to the control implementation, and you can define them to augment the control with a behavior specific to your needs.</p>

<pre><span class="code-preprocessor">#define XXS_BEMOREFANCY             0x0001
</span><span class="code-preprocessor">#define XXS_HIGHESTCUSTOMSTYLE      0x8000</span></pre>

<h3>Notifications</h3>

<p>If the custom control needs to notify the application about some events or changes of its state, or if it needs to ask the application about something, it may send the standard notification message (<code>WM_NOTIFY</code>). Of course it has to follow the contract the message provides to the application, i.e., <code>WPARAM</code> must specify the ID of the control, and <code>LPARAM</code> must point to <code>NMHDR</code> or a control-specific structure which begins with that.</p>

<p>The typical code of custom control sending the notifications may look like this:</p>

<pre lang="C"><span class="code-keyword">static</span> <span class="code-keyword">void</span>
CommonSendSomeNotification(HWND hwnd)
{
    NMHDR hdr;

    hdr.hwndFrom = hwnd;  <span class="code-comment">//</span><span class="code-comment"> The custom control handle</span>
    hdr.idFrom = GetWindowLong(hwnd, GWL_ID);
    hdr.code = XXN_NOTIFICATIONCODE;
    SendMessage(GetParent(hwnd), WM_NOTIFY, hdr.idFrom, (LPARAM) &amp;hdr);
}</pre>

<p>As part of the control interface, the code <code>XXN_NOTIFICATIONCODE</code> should of course be defined in a header describing the control's interface. Note that unlike for messages, Win32 API does not define any ranges for the notifications. But if you take a look into the Windows SDK headers, you may see the standard notification codes have the most significant bit set (they are defined as a negative number cast to <code>UINT</code>), so if you define control-specific notifications in a range from 0 to 0x7fffffff, there is no danger of clash with system notification codes.</p>

<pre><span class="code-preprocessor">#define XXN_NOTIFICATIONCODE                   0x1</span></pre>

<h2>Real Life Code</h2>

<p>Nothing can replace the possibility to study real-life code and indeed when implementing a full-featured custom control, you will probably need it more than once. I can provide you two pointers which (I hope) can serve as good examples. The first one is the Wine (<a href="http://www.winehq.org/">http://www.winehq.org</a>) project, especially its (re)implementation of <em>USER32.DLL</em> and <em>COMCTL32.DLL</em>:</p>

<ul>
	<li><a href="https://github.com/mirrors/wine/tree/master/dlls/user32">https://github.com/mirrors/wine/tree/master/dlls/user32</a></li>	<li><a href="https://github.com/mirrors/wine/tree/master/dlls/comctl32">https://github.com/mirrors/wine/tree/master/dlls/comctl32</a></li></ul>

<p>In the context of custom controls the Wine project is valuable in two different ways: First, you can see the code as an implementation of any other custom control. Second, and perhaps even more importantly, as the Wine tries to be as much compatible with native Windows implementation as possible, its sources are also great if you want to design your custom control as consistent as possible with native Windows controls. They can serve as a good illustration for what those control can or cannot do. And believe me: The Wine code is in many regards much more complete than any documentation available on MSDN or elsewhere.</p>

<p>So, for example, if you implement a control "which should look a bit like tree-view" but "it is too much different to just customize the standard tree-view through subclassing", then studying the Wine's implementation of tree control may be the right thing where to start.</p>

<p>The second pointer is a soup served (mainly) by me. It is the mCtrl project (<a href="http://mctrl.sourceforge.net/">http://mctrl.org</a>) which implements several custom controls. By no means is the project finished, but it can already serve well as an illustrative code for purposes of this article series. And it is also no accident as this article as well as the follow-up articles I plan to write are based on the experience I've got during its development. The project code is hosted on github and it provides both the implementation of the custom controls (subdirectory <em>src</em>) as well as simple example apps illustrating the usage (subdirectory <em>examples</em>):</p>

<ul>
	<li><a href="https://github.com/mity/mctrl/tree/master/src">https://github.com/mity/mctrl/</a></li></ul>

<p>Both projects are open source, and of course you may also reuse and modify the code in your project, assuming you will follow the license conditions of the project of your interest.</p>

<h2>Stay Tuned</h2>

<p>As already mentioned at the beginning of the article, this is just the first article of the series on the broad topic of custom control implementation. Next time, we will take a closer look at how to paint a custom control. Also (as it is quite a common trouble when implementing a new control) how to avoid flickering on frequent repainting, e.g., when the control is being resized.</p>


						</div>
						

						<div class="float-right" style="margin:20px 0 0 10px;border:1px solid #ccc">
						
						</div>
                        
                        
						
						<h2>License</h2>
						<div id="LicenseTerms"><p>This article, along with any associated source code and files, is licensed under <a href="http://www.codeproject.com/info/cpol10.aspx" rel="license">The Code Project Open License (CPOL)</a></p></div><h2 id="ctl00_AboutHeading">About the Author</h2>
						    

<div class="author-wrapper">

    <div class="pic-wrapper"> 
        <img id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberPhoto" class="profile-pic" src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/58de2d085c17e28b8951315245dd408c.jpeg" style="border-width:0px;transform:rotate(1deg);">
    </div>

    <div class="container-member">  
        <b><a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberProfileLink" class="author" href="https://www.codeproject.com/Members/Martin-Mitas">Martin Mitáš</a></b>

        <table>
        <tbody><tr>
            <td rowspan="2" nowrap="" valign="middle">
            <div id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowOn" class="follow">
	            
	            
	            <a href="https://www.linkedin.com/profile/view?id=88607525"><img style="vertical-align:middle;border:0;height:24px;width:24px" alt="LinkedIn" src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/linkedin-32.png"></a> 
            </div>
            </td>
            <td nowrap="nowrap">
                <div class="company">
                    <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberJobTitle">Team Leader</span>
	                <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberCompany"></span>
                </div>
            </td>
            <td rowspan="2" style="padding-left:15px">
                <a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_FollowBtn" title="Have events related to this Member appear in your timeline" class="button unfollowed align-center invisible" data-enabletooltip="true" data-tooltip="Have the articles and posts from this member appear in your Timeline so you can stay up to date." style="display:none;">Follow<div class="tiny-text" style="margin-top:-3px;">this Member</div></a>
	<a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_UnfollowBtn" title="Unfollow this Member" class="button followed align-center invisible" data-enabletooltip="true" data-tooltip="Stop following this Member" style="display:none;">Unfollow</a>

            </td>
        </tr>
        <tr>
            <td>
                <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberLocation">Czech Republic <img src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/CZ.gif" alt="Czech Republic" width="16px" height="11px"></span>
            </td>
        </tr>
        </tbody></table>
    </div>

    <div class="description">
        No Biography provided

        
    </div>

</div><br>
						
						

						<div class="clearfix"></div>

						<div style="padding-top:8px">
							
						</div>

					

				    
					</form>

				</div>

				
				<div class="bottom-promo"> 
				    
				</div>
				

                

				
				

					<h2>Comments and Discussions</h2>
					
					<p><img alt="Comment" src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/NewComment.gif" width="12px" height="16px">
					<b>26 messages</b> have been posted for this article 
					Visit <b><a id="ctl00_ArticleLink" href="https://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics">https://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics</a></b> to post and view comments on 
					this article, or click <b><a id="ctl00_PrintWithMessage" href="https://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics?display=PrintAll">here</a></b> 
					to get a print view with messages.</p>
					
				

			</div>
			
		</td>
		<td width="170px" class="article-wing-right">
			
		</td>
		</tr></tbody></table>

		
		<div class="theme1-background" style="height:2px" id="stickyStop"></div>

		<div class="extended tiny-text">
			<div class="row">
				<div class="float-left">
					<a id="ctl00_PermaLink" href="https://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics">Permalink</a> | 
					<a id="ctl00_AdvertiseLink" href="http://developermedia.com/">Advertise </a> |
					<a id="ctl00_PrivacyLink" href="https://www.codeproject.com/info/privacy.aspx">Privacy</a> |
    				<a id="ctl00_CookiePolicyLink" href="https://www.codeproject.com/info/cookies.aspx">Cookies</a> |
                    <a id="ctl00_TermsOfUseLink" href="https://www.codeproject.com/info/TermsOfUse.aspx">Terms of Use</a> |
					<a id="ctl00_Mobile">Mobile</a>
					<br>
								
					
					Web06 |
					2.8.181119.1 |
					Last Updated 12 Dec 2014								
				</div>

                      

				<div class="float-right align-right">
					Article Copyright 2013 by Martin Mitáš<br>Everything else
					Copyright © <a href="mailto:webmaster@codeproject.com">CodeProject</a>, 1999-2018 <br>
				</div>

				

			</div>
		</div>
		

		<br clear="all">
		
			

	</div> 
	</div>
</div>






<script type="text/javascript" src="./Custom Controls in Win32 API_ The Basics - CodeProject_files/MemberProfilePopup.min.js.下载"></script>
<script type="text/javascript">//<![CDATA[
$(document).ready(function () {
   processCodeBlocks.Initialise('#contentdiv');
   thumbnailer.Initialise('#contentdiv',700,600);
});
cookieconsent.initialise({
                                enabled : true,
                                cookie  : { domain: 'codeproject.com' },
                                palette : {
                                    popup: { background: '#ff9900' },
                                    button: { background: '#f5d948' }
                                },
                                law :  {
                                    showForAllRegions : true, 
                                    countryCode : 'CN' 
                                },
                                theme: 'edgeless',
                                type : 'opt-in',
                                content: {
                                    message: 'Like every other website we use cookies. By using our site you acknowledge that you have read and understand our <a href=\'/info/cookie.aspx\'>Cookie Policy</a>, <a href=\'/info/privacy.aspx\'>Privacy Policy</a>, and our <a href=\'/info/TermsOfUse.aspx\'>Terms of Service</a>.',
                                    href:    'https://www.codeproject.com/info/privacy.aspx'
                                },
                                revokable:true,
                                onStatusChange: function(status) {
                                    $.ajax({
                                		dataType  : 'json',
                                        data: JSON.stringify({ allowCookies : this.hasConsented() }),
                                        url: '/script/Common/webservices/CommonServices.aspx/SetCookieConsent',
                                        cache: false,
                                        type: 'POST',
                                        contentType: 'application/json'
                                    })
                                    console.log(this.hasConsented() ? 'enable cookies' : 'disable cookies');
                                    console.log(this.hasAnswered() ? 'has answered' : 'did not answer');
                                },
                            });
$(document).ready(function() { anchorAnimate();
});
$(document).ready(function(){
    $('#__EVENTVALIDATION').attr('autocomplete', 'off');
});
$(function() {
                        var followServicectl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember = new FollowService('/script/follow/webservices/followServices.aspx/', true);
                        followServicectl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember.initFollowObjectButtons({
                            item : { 
                                objectTypeId   : 1,
                                objectId       : 5807385
                            },
                            followButtonId   : 'ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_FollowBtn',
                            unfollowButtonId : 'ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_UnfollowBtn'
                        }, false);
                    });

//]]>
</script>





<div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div><div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div><div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div></body></html>